#include "vector3.h"

vector3::vector3()
{
	x = y = z = 0.0f;
}
vector3::vector3(double XYZ)
{
	x = y = z = XYZ;
}
vector3::vector3(double X, double Y, double Z)
{
	x = X;
	y = Y;
	z = Z;
}
vector3::vector3(point P1, point P2)
{
	x = P2.x - P1.x;
	y = P2.y - P1.y;
	z = P2.z - P1.z;
}
vector3::vector3(point P)
{
	x = P.x;
	y = P.y;
	z = P.z;
}
vector3::~vector3(){}

void vector3::normalize()
{
	double temp(this->width());
	if (temp!=0.0)
	{
		this->x /= temp;
		this->y /= temp;
		this->z /= temp;
	}
}
double vector3::width()
{
	return sqrt((this->x * this->x) + (this->y * this->y) + (this->z * this->z));
}
void vector3::set(double X, double Y, double Z)
{
	this->x = X;
	this->y = Y;
	this->z = Z;
}
void vector3::positive()
{
	this->x = +this->x;
	this->y = +this->y;
	this->z = +this->z;
}
void vector3::negative()
{
	this->x = -(this->x);
	this->y = -(this->y);
	this->z = -(this->z);
}
void vector3::mul(vector3 vector)
{

	this->x = this->x * vector.x;
	this->y = this->y * vector.y;
	this->z = this->z * vector.z;
}
void vector3::mulByScalar(double scalar)
{
	this->x = this->x * scalar;
	this->y = this->y * scalar;
	this->z = this->z * scalar;
}
void vector3::div(vector3 vector)
{
	if(vector.x !=0.0)
		this->x = this->x / vector.x;
	if(vector.y !=0.0)
		this->y = this->y / vector.y;
	if(vector.z !=0.0)
		this->z = this->z / vector.z;
}
void vector3::divByScalar(double scalar)
{
	if(scalar != 0.0)
	{
		this->x = this->x / scalar;
		this->y = this->y / scalar;
		this->z = this->z / scalar;
	}
	else
	{
		this->x = 0.0;
		this->y = 0.0;
		this->z = 0.0;
	}
}
void vector3::add(vector3 vector)
{
	this->x = this->x + vector.x;
	this->y = this->y + vector.y;
	this->z = this->z + vector.z;
}
void vector3::sub(vector3 vector)
{
	this->x = this->x - vector.x;
	this->y = this->y - vector.y;
	this->z = this->z - vector.z;
}
void vector3::cross(vector3 vector)
{
	vector3 temp;
	temp.x = (this->y * vector.z) - (this->z * vector.y);
	temp.y = (this->z * vector.x) - (this->x * vector.z);
	temp.z = (this->x * vector.y) - (this->y * vector.x);
	this->x = temp.x;
	this->y = temp.y;
	this->z = temp.z;
}
vector3 vector3::cross2(vector3 vector)
{
	vector3 temp;
	temp.x = (this->y * vector.z) - (this->z * vector.y);
	temp.y = (this->z * vector.x) - (this->x * vector.z);
	temp.z = (this->x * vector.y) - (this->y * vector.x);
	return temp;
}
double vector3::dot(vector3 vector)
{
	return (this->x * vector.x) + (this->y * vector.y) + (this->z * vector.z);
}
void vector3::lerp(vector3 v, float t)
{
	this->x = this->x + t * (v.x - this->x);
	this->y = this->y + t * (v.y - this->y);
	this->z = this->z + t * (v.z - this->z);
}
void vector3::copyFromPoint(point P)
{
	this->x = P.x;
	this->y = P.y;
	this->z = P.z;
}
point vector3::movePoint(point P)
{
	point temp;
	temp.x = P.x + this->x;
	temp.y = P.y + this->y;
	temp.z = P.z + this->z;
	return temp;
}
void vector3::getVector3FromXML(std::ifstream &file)
{
	char line[MAX_LENGTH];
	file.getline(line, MAX_LENGTH);
	std::string nazwaWezla;
	std::string temp(line);

	unsigned int i(0);

	while(temp[i] == 9 || temp[i] == 32)
		++i;

	++i;
	while(temp[i] != '>')
	{
		nazwaWezla.push_back(temp[i]);
		++i;
	}
	while (nazwaWezla!="/vector3")
	{
		file.getline(line, MAX_LENGTH);
		temp.clear();
		temp.append(line);
		nazwaWezla.clear();

		i=0;
		while(temp[i] == 9 || temp[i] == 32)
			++i;
		if(temp[i] == '<')
		{
			std::string nazwaWezlaKoniec;
			std::string zawartoscWezla;
			++i;
			while(temp[i] != '>')
			{
				nazwaWezla.push_back(temp[i]);
				++i;
			}
			if(nazwaWezla == "X")
			{
				++i;
				while(temp[i] != '<')
				{
					zawartoscWezla.push_back(temp[i]);
					++i;
				}
				++i;
				while(temp[i] != '>')
				{
					nazwaWezlaKoniec.push_back(temp[i]);
					++i;
				}
				if(nazwaWezlaKoniec == "/X")
					this->x = atof(zawartoscWezla.c_str());
				continue;
			}
			else if(nazwaWezla == "Y")
			{
				++i;
				while(temp[i] != '<')
				{
					zawartoscWezla.push_back(temp[i]);
					++i;
				}
				++i;
				while(temp[i] != '>')
				{
					nazwaWezlaKoniec.push_back(temp[i]);
					++i;
				}
				if(nazwaWezlaKoniec == "/Y")
					this->y = atof(zawartoscWezla.c_str());
				continue;
			}
			else if(nazwaWezla == "Z")
			{
				++i;
				while(temp[i] != '<')
				{
					zawartoscWezla.push_back(temp[i]);
					++i;
				}
				++i;
				while(temp[i] != '>')
				{
					nazwaWezlaKoniec.push_back(temp[i]);
					++i;
				}
				if(nazwaWezlaKoniec == "/Z")
					this->z = atof(zawartoscWezla.c_str());
				continue;
			}
		}
	}
}
void vector3::randomVector(double range)
{
	this->x = randNumber(2.0) - 1.0;
	this->y = randNumber(2.0) - 1.0;
	this->z = randNumber(2.0) - 1.0;
	this->normalize();
	(*this)*=range;
}
void vector3::randomDirectedVector(double range, vector3 N)
{
	vector3 temp;
	double dot(-1);
	while(dot<0)
	{
		this->x = randNumber(2.0) - 1.0;
		this->y = randNumber(2.0) - 1.0;
		this->z = randNumber(2.0) - 1.0;
		this->normalize();
		dot = this->dot(N);
	}
	(*this)*=range;
}
//++//++//++//++//++//++//++//++//++//++//++//++//++//++//++//++//++//++//++//++//++
//Operators
//++//++//++//++//++//++//++//++//++//++//++//++//++//++//++//++//++//++//++//++//++
vector3 vector3::operator+()
{
	positive();
	return	vector3(x,y,z);
}
vector3 vector3::operator-()
{
	negative();
	return	vector3(x,y,z);
}
vector3 vector3::operator+( const vector3 &other )
{
	return vector3(this->x + other.x, this->y + other.y, this->z + other.z);
}
vector3 & vector3::operator+=( const vector3 &other )
{
	this->x += other.x;
	this->y += other.y;
	this->z	+= other.z;
	return *this;
}
vector3 vector3::operator-( const vector3 &other )
{
	return vector3(this->x - other.x, this->y - other.y, this->z - other.z);
}
vector3 & vector3::operator-=( const vector3 &other )
{
	this->x -= other.x;
	this->y -= other.y;
	this->z	-= other.z;
	return *this;
}
vector3 vector3::operator*( const vector3 &other )
{
	vector3 temp;
	temp.x = this->x * other.x;
	temp.y = this->y * other.y;
	temp.z = this->z * other.z;
	return temp;
}
vector3 vector3::operator*( const double &scalar )
{
	vector3 temp;
	temp.x = this->x * scalar;
	temp.y = this->y * scalar;
	temp.z = this->z * scalar;
	return temp;
}
vector3 vector3::operator*( const float &scalar )
{
	vector3 temp;
	temp.x = this->x * (double)scalar;
	temp.y = this->y * (double)scalar;
	temp.z = this->z * (double)scalar;
	return temp;
}
vector3 vector3::operator*( const int &scalar )
{
	vector3 temp;
	temp.x = this->x * (double)scalar;
	temp.y = this->y * (double)scalar;
	temp.z = this->z * (double)scalar;
	return temp;
}
vector3 vector3::operator*( const matrix4 &matrix )
{
	vector3 temp;
	double w(1.0);
	temp.x = this->x*matrix._00 + this->y*matrix._01 + this->z*matrix._02 + w*matrix._03;
	temp.y = this->x*matrix._10 + this->y*matrix._11 + this->z*matrix._12 + w*matrix._13;
	temp.z = this->x*matrix._20 + this->y*matrix._21 + this->z*matrix._22 + w*matrix._23;
	return temp;
}
vector3 & vector3::operator*=( const vector3 &other )
{
	this->x *= other.x;
	this->y *= other.y;
	this->z *= other.z;
	return *this;
}
vector3 & vector3::operator*=( const double &scalar )
{
	this->x *= scalar;
	this->y *= scalar;
	this->z *= scalar;
	return *this;
}
vector3 & vector3::operator*=( const float &scalar )
{
	this->x *= (double)scalar;
	this->y *= (double)scalar;
	this->z *= (double)scalar;
	return *this;
}
vector3 & vector3::operator*=( const int &scalar )
{
	this->x *= (double)scalar;
	this->y *= (double)scalar;
	this->z *= (double)scalar;
	return *this;
}
vector3 vector3::operator/( const vector3 &other )
{
	vector3 temp;
	temp.x = this->x / other.x;
	temp.y = this->y / other.y;
	temp.z = this->z / other.z;
	return temp;
}
vector3 vector3::operator/( const double &scalar )
{
	vector3 temp;
	temp.x = this->x / scalar;
	temp.y = this->y / scalar;
	temp.z = this->z / scalar;
	return temp;
}
vector3 vector3::operator/( const float &scalar )
{
	vector3 temp;
	temp.x = this->x / (double)scalar;
	temp.y = this->y / (double)scalar;
	temp.z = this->z / (double)scalar;
	return temp;
}
vector3 vector3::operator/( const int &scalar )
{
	vector3 temp;
	temp.x = this->x / (double)scalar;
	temp.y = this->y / (double)scalar;
	temp.z = this->z / (double)scalar;
	return temp;
}
vector3 & vector3::operator/=( const vector3 &other )
{
	this->x /= other.x;
	this->y /= other.y;
	this->z /= other.z;
	return *this;
}
vector3 & vector3::operator/=( const double &scalar )
{
	this->x /= scalar;
	this->y /= scalar;
	this->z /= scalar;
	return *this;
}
vector3 & vector3::operator/=( const float &scalar )
{
	this->x /= (double)scalar;
	this->y /= (double)scalar;
	this->z /= (double)scalar;
	return *this;
}
vector3 & vector3::operator/=( const int &scalar )
{
	this->x /= (double)scalar;
	this->y /= (double)scalar;
	this->z /= (double)scalar;
	return *this;
}
vector3 & vector3::operator=( const vector3 &other )
{
	this->x = other.x;
	this->y = other.y;
	this->z = other.z;
	return *this; 
}
vector3 & vector3::operator=( const point &P )
{
	this->x = P.x;
	this->y = P.y;
	this->z = P.z;
	return *this; 
}
bool vector3::operator==( const vector3 &other )
{
	if ( (this->x == other.x) && (this->y == other.y) && (this->z == other.z))
		return true;
	else 
		return false;
}
bool vector3::operator!=( const vector3 &other )
{
	if ( (this->x == other.x) && (this->y == other.y) && (this->z == other.z))
		return false;
	else 
		return true;
}
bool vector3::operator>( vector3 &other )
{
	if (this->width() > other.width())
		return true;
	else
		return false;
}
bool vector3::operator<( vector3 &other )
{
	if (this->width() < other.width())
		return true;
	else
		return false;
}
bool vector3::operator>=( vector3 &other )
{
	if (this->width() >= other.width())
		return true;
	else
		return false;
}
bool vector3::operator<=( vector3 &other )
{
	if (this->width() <= other.width())
		return true;
	else
		return false;
}